/*
   Copyright (c) [Year] [name of copyright holder]
   [Software Name] is licensed under Mulan PSL v2.
   You can use this software according to the terms and conditions of the Mulan PSL v2. 
   You may obtain a copy of Mulan PSL v2 at:
            http://license.coscl.org.cn/MulanPSL2 
   THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.  
   See the Mulan PSL v2 for more details.  
*/

#ifndef JIAJIA_IR_HPP
#define JIAJIA_IR_HPP

#include"jiajiastd.hpp"
#include"jjtoken.hpp"

namespace jiajia{

    class jjirnode{
    public:
        enum IRFACTORENUM{
            IR_BEGIN = 0,
            IR_UNARY_VALUE = IR_BEGIN,
            IR_UNARY_RESULT,
            IR_UNARY_END,

            IR_EXPR_LHS = IR_BEGIN,
            IR_EXPR_RHS,
            IR_EXPR_RESULT,
            IR_EXPR_END,

            IR_IF_COND = IR_BEGIN,
            IR_IF_GOTO,
            IR_IF_END,

            // GOTO
            IR_GOTO = IR_BEGIN,
            IR_GOTO_END,

            // GOTONEXT
            IR_GOTONEXT_END = IR_BEGIN,

            // 因为 Table 类型，节点的 RHS 为字符串比较特殊，所以用这表示
            IR_TABLE_LHS = IR_BEGIN,
            IR_TABLE_RHS,
            IR_TABLE_RESULT,
            IR_TABLE_END,

            // 调用函数
            IR_CALL_FUNC = IR_BEGIN,
            IR_CALL_RESULT,
            IR_CALL_END,

            // 全局操作
            IR_GLOBAL_NAME = IR_BEGIN,
            IR_GLOBAL_RESULT,
            IR_GLOBAL_END,

            // 新的函数调用
            IR_ARGNEW_END = IR_BEGIN,

            // 压入参数
            IR_ARGPUSH_VAL = IR_BEGIN,
            IR_ARGPUSH_END
        };

        static const size_t attr_size = my::intMax<IR_UNARY_END, IR_EXPR_END, IR_GOTO_END, IR_TABLE_END, IR_CALL_END, IR_GLOBAL_END, IR_ARGNEW_END, IR_ARGPUSH_END>::value;

        union valueType{
            long num;
            value_t * value;
            jjirnode * node;
            string_t * str;
            func_t func;
        };

        jjtoken mToken;                 // 该 token 记录着该节点对应着源代码的信息
        code_t mCode;                   // 该 code 为指令
        valueType mAttr[attr_size];     // attr 为指令所对应的参数
        jjirnode * mNext;               // 下一个节点
        jjirnode * mBack;               // 上一个节点

        jjirnode():mCode(code::GOTONEXT), mNext(nullptr), mBack(nullptr){}

        ~jjirnode(){
            free();
        }

        inline void free(){
            switch(mCode){
            case code::EMPTY: return;
            case code::MINUS:
            case code::ASSIGN:
            case code::TOBOOL:
                mem::free(mAttr[IR_UNARY_VALUE].value);
                mem::free(mAttr[IR_UNARY_RESULT].value);
                break;
            case code::ADD:
            case code::SUB:
            case code::MULT:
            case code::DEV:
            case code::EQ:
            case code::GT:
            case code::LT:
            case code::GE:
            case code::LE:
            case code::PUSH:
            case code::AT:
                mem::free(mAttr[IR_EXPR_LHS].value);
                mem::free(mAttr[IR_EXPR_RHS].value);
                mem::free(mAttr[IR_EXPR_RESULT].value);
                break;
            case code::FIND:
            case code::INSERT:
                mem::free(mAttr[IR_TABLE_LHS].value);
                mem::free(mAttr[IR_TABLE_RESULT].value);
                break;
            case code::IFTRUE:
            case code::IFFALSE:
                mem::free(mAttr[IR_IF_COND].value);
                break;
            case code::CALL:
                mem::free(mAttr[IR_CALL_RESULT].value);
                break;
            case code::GFIND:
            case code::GINSERT:
                mem::free(mAttr[IR_GLOBAL_RESULT].value);
                break;
            default:
                break;
            }
        }
        
    public:

        inline long num(enum_t e){
            return mAttr[e].num;
        }

        inline string_t * str(enum_t e){
            return mAttr[e].str;
        }

        inline jjirnode * node(enum_t e){
            return mAttr[e].node;
        }

        inline value_t * value(enum_t e){
            return mAttr[e].value;
        }

        inline func_t func(enum_t e){
            return mAttr[e].func;
        }

        void setToken(const jjtoken & t){
            mToken = t;
        }

        void genUNARY(const code_t code, value_t * val, value_t * result_val){
            free();
            mCode = code;
            mAttr[IR_UNARY_VALUE].value = mem::up(val);
            mAttr[IR_UNARY_RESULT].value = mem::up(result_val);
        }

        void genEXPR(const code_t code, value_t * lhs_val, value_t * rhs_val, value_t * result_val){
            free();
            mCode = code;
            mAttr[IR_EXPR_LHS].value = mem::up(lhs_val);
            mAttr[IR_EXPR_RHS].value = mem::up(rhs_val);
            mAttr[IR_EXPR_RESULT].value = mem::up(result_val);
        }

        void genIF(const code_t code, value_t * cond_val, jjirnode * goto_node){
            free();
            mCode = code;
            mAttr[IR_IF_COND].value = mem::up(cond_val);
            mAttr[IR_IF_GOTO].node = goto_node;
        }

        void genTABLE(const code_t code, value_t * lhs_val, string_t * rhs_str, value_t * result_val){
            free();
            mCode = code;
            mAttr[IR_TABLE_LHS].value = mem::up(lhs_val);
            mAttr[IR_TABLE_RHS].str = rhs_str;
            mAttr[IR_TABLE_RESULT].value = mem::up(result_val);
        }

        void genGOTO(jjirnode * goto_node){
            free();
            mCode = code::GOTO;
            mAttr[IR_GOTO].node = goto_node;
        }

        void genGOTONEXT(){
            free();
            mCode = code::GOTONEXT;
        }

        // 函数的一些指令
        void genCALL(func_t f, value_t * result_val){
            free();
            mCode = code::CALL;
            mAttr[IR_CALL_FUNC].func = f;
            mAttr[IR_CALL_RESULT].value = mem::up(result_val);
        }

        void genARGNEW(){
            free();
            mCode = code::ARGNEW;
        }

        void genARGPUSH(value_t * val){
            free();
            mCode = code::ARGPUSH;
            mAttr[IR_ARGPUSH_VAL].value = mem::up(val);
        }

        // 全局变量的操作
        void genGLOBAL(const code_t code, string_t * name, value_t * result_val){
            free();
            mCode = code;
            mAttr[IR_GLOBAL_NAME].str = name;
            mAttr[IR_GLOBAL_RESULT].value = mem::up(result_val);
        }

        bool backfillResult(value_t * result_val){
            switch(mCode){
            case code::MINUS:
            case code::ASSIGN:
                mem::down(mAttr[IR_UNARY_RESULT].value);
                mAttr[IR_UNARY_RESULT].value = result_val;
                return true;
            case code::FIND:
            case code::INSERT:
                mem::down(mAttr[IR_TABLE_RESULT].value);
                mAttr[IR_TABLE_RESULT].value = result_val;
                return true;
            case code::ADD:
            case code::SUB:
            case code::MULT:
            case code::DEV:
            case code::EQ:
            case code::GT:
            case code::LT:
            case code::GE:
            case code::LE:
            case code::PUSH:
            case code::AT:
                mem::down(mAttr[IR_EXPR_RESULT].value);
                mAttr[IR_EXPR_RESULT].value = result_val;
                return true;
            case code::GFIND:
            case code::GINSERT:
                mem::down(mAttr[IR_GLOBAL_RESULT].value);
                mAttr[IR_GLOBAL_RESULT].value = result_val;
                return true;
            default: return false;
            }
        }

        bool backfillGoto(jjirnode * goto_ir){
            switch(mCode){
            case code::IFTRUE:
            case code::IFFALSE:
                mAttr[IR_IF_GOTO].node = goto_ir;
                break;
            case code::GOTO:
                mAttr[IR_GOTO].node = goto_ir;
                break;
            default: return false;
            }
            return true;
        }

        void GFIND2FIND(value_t * table){
            if(mCode != code::GFIND) return ;

            string_t * name = mAttr[IR_GLOBAL_NAME].str;
            value_t * result = mem::up(mAttr[IR_GLOBAL_RESULT].value);

            this->genTABLE(code::FIND, table, name, result);
            mem::down(result);
        }

        // 注意，会把所有 code::FIND -> code::INSERT，其他不变
        static void ToLHExpr(jjirnode * begin, jjirnode * end){
            while(begin != end->mNext && begin != nullptr){
                if(begin->mCode == code::FIND){
                    begin->mCode = code::INSERT;
                }else if(begin->mCode == code::GFIND){
                    begin->mCode = code::GINSERT;
                }
                begin = begin->mNext;
            }
        }
    };

    std::ostream & operator<<(std::ostream & os, const jjirnode & node){
        os<<&node<<": ["<<node.mToken<<", "<<code::code_str[node.mCode];
        switch(node.mCode){
        case code::MINUS:
        case code::ASSIGN:
        case code::TOBOOL:
        case code::NO:
            os<<", "<<node.mAttr[jjirnode::IR_UNARY_VALUE].value
              <<", "<<node.mAttr[jjirnode::IR_UNARY_RESULT].value;
            break;
        case code::FIND:
        case code::INSERT:
            os<<", "<<node.mAttr[jjirnode::IR_TABLE_LHS].value
              <<", "<<*node.mAttr[jjirnode::IR_TABLE_RHS].str
              <<", "<<node.mAttr[jjirnode::IR_TABLE_RESULT].value;
            break;
        case code::ADD:
        case code::SUB:
        case code::MULT:
        case code::DEV:
        case code::EQ:
        case code::GT:
        case code::LT:
        case code::GE:
        case code::LE:
        case code::PUSH:
        case code::AT:
            os<<", "<<node.mAttr[jjirnode::IR_EXPR_LHS].value
              <<", "<<node.mAttr[jjirnode::IR_EXPR_RHS].value
              <<", "<<node.mAttr[jjirnode::IR_EXPR_RESULT].value;
            break;
        case code::GFIND:
        case code::GINSERT:
            os<<", "<<*node.mAttr[jjirnode::IR_GLOBAL_NAME].str
              <<", "<<node.mAttr[jjirnode::IR_GLOBAL_RESULT].value;
            break;
        case code::IFFALSE:
        case code::IFTRUE:
            os<<", "<<node.mAttr[jjirnode::IR_IF_COND].value
              <<", "<<node.mAttr[jjirnode::IR_IF_GOTO].node;
            break;
        case code::CALL:
            os<<", "<<(void *)node.mAttr[jjirnode::IR_CALL_FUNC].func
              <<", "<<node.mAttr[jjirnode::IR_CALL_RESULT].value;
            break;
        case code::GOTO:
            os<<", "<<node.mAttr[jjirnode::IR_GOTO].node;
            break;
        case code::ARGPUSH:
            os<<", "<<node.mAttr[jjirnode::IR_ARGPUSH_VAL].value;
            break;
        default: break;
        }
        os<<"]";
        return os;
    }

    // 该类将是 jiajia 从前端转换成 ir 存储位置的源代码
    class jjir{
    private:
        jjirnode * mHead;
        jjirnode * mEnd;

        jjir(const jjir & rhs) = delete;
        jjir(jjir && rhs) = delete;

        static jjirnode ** Find(jjirnode * head, jjirnode * node){
            jjirnode ** cur = &head;
            while(*cur != nullptr && *cur != node){
                cur = &(*cur)->mNext;
            }
            return cur;
        }

        static jjirnode ** FindForward(jjirnode * head, jjirnode * node){
            jjirnode ** cur = &head;
            while(*cur != nullptr && (*cur)->mNext != node){
                cur = &(*cur)->mNext;
            }
            return cur;
        }

        // 检查当前节点是否为预留节点
        static inline bool IsKeepNode(jjirnode * node){
            if(node != nullptr)
                return node->mCode == code::EMPTY || node->mCode == code::GOTONEXT;
            return false;
        }

    public:
        jjir():mHead(nullptr), mEnd(nullptr){}
        ~jjir(){ free(); }

        inline jjirnode * head() const {
            return mHead;
        }

        // 向上一次插入的地方前面插入
        // jjirnode * insertLastForward(){
        //     jjirnode * tmp = mem::calloc<jjirnode>(1);
        //     tmp->mNext = *mLast;
        //     *mLast = tmp;
        //     return tmp;
        // }

        // 向上一次插入的地方后面插入
        // jjirnode * insertLastBack(){
        //     jjirnode * tmp = mem::calloc<jjirnode>(1);
        //     tmp->mNext = (*mLast)->mNext;
        //     (*mLast)->mNext = tmp;
        //     mLast = &(*mLast)->mNext;
        //     return tmp;
        // }

        // 向链表新建一个 node, 在链表最后面添加
        // 如果最后一个 node 属于 keep ，则返回其
        jjirnode * insert(){
            if(!IsKeepNode(mEnd)){
                jjirnode * tmp = mem::calloc<jjirnode>(1);
                if(mEnd == nullptr)
                    mEnd = mHead = tmp;
                else{
                    mEnd->mNext = tmp;
                    tmp->mBack = mEnd;
                    mEnd = tmp;
                }
            }
            return mEnd;
        }

        // 向某个节点前面插入新节点
        // 如果 node == nullptr, 统一插到最后面
        jjirnode * insertBack(jjirnode * node){
            if(node == nullptr){
                return insert();
            }else{
                if(IsKeepNode(node->mBack)){
                    return node->mBack;
                }else{
                    jjirnode * tmp = mem::calloc<jjirnode>(1);

                    tmp->mNext = node;
                    tmp->mBack = node->mBack;
                    node->mBack = tmp;

                    // 当 node->mBack == nullptr，则证明 node 为第一个节点
                    // 那 tmp 则变为第一个节点
                    if(tmp->mBack != nullptr)
                       tmp->mBack->mNext = tmp;
                    else
                        mHead = tmp;
                    return tmp;
                }
            }
        }

        // 向某个节点后面插入
        // 如果 node == nullptr, 统一插到最后面
        jjirnode * insertNext(jjirnode * node){
            if(node == nullptr){
                return insert();
            }else{
                if(IsKeepNode(node->mNext)){
                    return node->mNext;
                }else{
                    jjirnode * tmp = mem::calloc<jjirnode>(1);
                    tmp->mNext = node->mNext;
                    tmp->mBack = node;
                    node->mNext = tmp;

                    // 当 node->mNext == nullptr, 则证明 node 为最后一个节点
                    // 那 tmp 则变为第二个节点
                    if(tmp->mNext != nullptr)
                        tmp->mNext->mBack = tmp;
                    else
                        mEnd = tmp;
                    return tmp;
                }
            }
        }

        // 获得某个节点的下一个预留节点
        // 如果没有预留节点，就预留一个节点
        // 如果有预留节点，就返回该预留节点
        jjirnode * keepNext(jjirnode * node){
            node = insertNext(node);
            node->genGOTONEXT();
            return node;
        }

        // 释放
        void free(){
            jjirnode * head = mHead;
            jjirnode * cur = mHead;
            while(cur != nullptr){
                head = head->mNext;

                cur->mNext = nullptr;
                mem::free(cur);
                cur = head;
            }

            mHead = nullptr;
            mEnd = nullptr;
            // mLast = &mHead;
        }
    };

    std::ostream & operator<<(std::ostream & os, const jjir & ir){
        os<<"{\n";
        jjirnode * node = ir.head();
        while(node != nullptr){
            os<<"\t["<<(*node)<<"]"<<std::endl;
            node = node->mNext;
        }
        os<<"}";
        return os;
    }
}

#endif
